package com.ytg.myprocess.model;

import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import com.ytg.myprocess.TypeUtil;

import java.util.ArrayList;
import java.util.List;

import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;

public class AnnotatedClass {

    /**
     * 类名
     */
    public TypeElement mClassElement;
    /**
     * 成员变量
     */
    public List<BindViewField> mFiled;
    /**
     * 方法
     */
    public List<OnClickMethod> mMethod;
    /**
     * 元素帮助类
     */
    public Elements mElementUtils;

    // 在BindViewProcessor中可知, 一个fullClassName对应一个AnnotatedClass.
    public AnnotatedClass(TypeElement classElement, Elements elementUtils) {
        this.mClassElement = classElement;
        this.mElementUtils = elementUtils;
        this.mFiled = new ArrayList<>();
        this.mMethod = new ArrayList<>();
    }

    public String getFullClassName() {
        return mClassElement.getQualifiedName().toString();
    }

    public void addField(BindViewField field) {
        mFiled.add(field);
    }

    public void addMethod(OnClickMethod method) {
        mMethod.add(method);
    }
    public static boolean isFromType(TypeName requestType, TypeName expectedType) {
        System.out.println(requestType.getClass()+"------------1-----------"+expectedType.getClass() );
        try {
            System.out.println("------------" +
                            requestType.getClass().isAssignableFrom(expectedType.getClass()));
//            if(Class.forName(requestType.toString()).isInstance( Class.forName(expectedType.toString()))){
//                System.out.println("------------true-----------");
//                return true;
//            }
        } catch (Exception e) {
            e.printStackTrace();
        }
//        if(requestType instanceof ParameterizedTypeName) {
//            System.out.println("-----------------------");
//            TypeName typeName = ((ParameterizedTypeName) requestType).rawType;
//            System.out.println(expectedType+"-----------------------"+typeName);
//            return (typeName.equals(expectedType));
//        }

        return false;
    }
    // 生成对应的java文件
    public JavaFile generateFinder() {
//        FieldSpec fieldSpec = FieldSpec.builder(ParameterizedTypeName.get(LinkedHashMap.class, Integer.class, String.class), "mapViewFeild")
//                .addModifiers(Modifier.PUBLIC)
//                .initializer("new $T<>()", LinkedHashMap.class)
//                .build();
        ClassName view = ClassName.get("android.view", "View");
        ClassName linkedHashMap = ClassName.get("java.util", "LinkedHashMap");
        ClassName string = ClassName.get("java.lang", "String");
//        ClassName Integer = ClassName.get("java.lang", "Integer");
        ClassName TextView = ClassName.get("android.widget", "TextView");
        ClassName arrayList = ClassName.get("java.util", "ArrayList");
        ClassName ViewGroup = ClassName.get("android.view", "ViewGroup");
//        ClassName AppCompatDelegate = ClassName.get("androidx.appcompat.app", "AppCompatDelegate");
        FieldSpec fieldSpec2 = FieldSpec.builder(ParameterizedTypeName.get(linkedHashMap, string, view), "mapFeildView")
                .addModifiers(Modifier.PUBLIC)
                .initializer("new $T<>()", linkedHashMap)
                .build();
        FieldSpec fieldSpec9 = FieldSpec.builder(ParameterizedTypeName.get(linkedHashMap, string, string), "mapFeildVType")
                .addModifiers(Modifier.PUBLIC)
                .initializer("new $T<>()", linkedHashMap)
                .build();
        FieldSpec fieldSpec3 = FieldSpec.builder(ParameterizedTypeName.get(ClassName.get("androidx.databinding", "ObservableArrayMap"), string, string), "mapViewData")
                .addModifiers(Modifier.PRIVATE)
                .initializer("new $T<>()", ClassName.get("androidx.databinding", "ObservableArrayMap"))
                .build();
        FieldSpec fieldSpec4 = FieldSpec.builder(ParameterizedTypeName.get(ClassName.get("androidx.databinding", "ObservableMap"), string, string), "observableMap")
                .addModifiers(Modifier.PUBLIC)
                .build();
        FieldSpec fieldSpec5 =  FieldSpec.builder(boolean.class, "notify", Modifier.PRIVATE).initializer("true").build();
//        FieldSpec fieldSpec6 =  FieldSpec.builder(boolean.class, "notifyMap", Modifier.PRIVATE).initializer("true").build();
        FieldSpec fieldSpec10 = FieldSpec.builder(ParameterizedTypeName.get(arrayList, TextView), "sonview")
                .addModifiers(Modifier.PUBLIC)
                .initializer("new $T<>()", arrayList)
                .build();
        FieldSpec fieldSpec17 = FieldSpec.builder(ClassName.get("android.content", "Context"), "context")
                .addModifiers(Modifier.PUBLIC)
                .build();
        /**
         * 构建方法
         */
        MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("inject")
                .addModifiers(Modifier.PUBLIC)// 方法访问权限
                .addAnnotation(Override.class)// 方法的注解
                .returns(TypeUtil.INJECTOR) // 定义方法的返回值
                .addParameter(TypeName.get(mClassElement.asType()), "host", Modifier.FINAL) // 定义方法的参数
                .addParameter(TypeName.OBJECT, "source") // 定义方法的参数
                .addParameter(TypeUtil.FINDER, "finder")// 定义方法的参数
               ;
        /**
         * 遍历添加类成员
         */
        for (BindViewField field : mFiled) {// 定义方法内部的语句
            methodBuilder.addStatement("host.$N=($T)finder.findView(source,$L)", field.getFieldName()
                    , ClassName.get(field.getFieldType()), field.getResId());
            if(!field.key.equals("")){
                methodBuilder.addStatement("host.$N.setTag($S)", field.getFieldName()
                       ,"BTag:" +field.key);
//                methodBuilder.addStatement("mapViewFeild.put(host.$N.getId(), $S)", field.getFieldName(),field.key);
                methodBuilder.addStatement("mapFeildView.put($S,host.$N)", field.key,field.getFieldName());
                methodBuilder.addStatement("mapFeildVType.put($S,$S)", field.key,field.getFieldType().toString());
//                methodBuilder.addStatement("mapMethodSet.put($S,$S)", field.key,field.methodSet);
//                methodBuilder.addStatement("mapMethodGet.put($S,$S)", field.key,field.methodGet);
//                methodBuilder.addStatement("mapBindTag.put($S,$S)", field.key,field.bindTag);
//                if(field.getFieldType().toString().contains("RadioGroup")){
//                    methodBuilder.addStatement("host.$N.setOnCheckedChangeListener(new $T.OnCheckedChangeListener() {\n" +
//                            "            @Override\n" +
//                            "            public void onCheckedChanged(RadioGroup group, int checkedId) {\n" +
//                            "                   setData(group.getTag().toString().replace(\"BTag:\", \"\"),(($T)group.findViewById(checkedId)).getText().toString());\n" +
//                            "            }\n" +
//                            "        });", field.getFieldName(),ClassName.get("android.widget", "RadioGroup"),ClassName.get("android.widget", "RadioButton"));
//                }
//                if(field.getFieldType().toString().contains("CheckBox")){
//                    methodBuilder.addStatement("host.$N.setOnCheckedChangeListener(new $T.OnCheckedChangeListener() {\n" +
//                            "            @Override\n" +
//                            "            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {\n" +
//                            "                setData(buttonView.getTag().toString().replace(\"BTag:\", \"\"), isChecked+\"\");\n" +
//                            "            }\n" +
//
//                            "        });", field.getFieldName(),ClassName.get("android.widget", "CompoundButton"));
//
//                }
            }
        }
        /**
         * 声明Listener
         */
        if (mMethod.size() > 0) {// 定义方法内部的语句
            methodBuilder.addStatement("$T listener", TypeUtil.ONCLICK_LISTENER);
        }

        for (OnClickMethod method : mMethod) {
            TypeSpec listener = TypeSpec.anonymousClassBuilder("")
                    .addSuperinterface(TypeUtil.ONCLICK_LISTENER)
                    .addMethod(MethodSpec.methodBuilder("onClick")
                            .addAnnotation(Override.class)
                            .addModifiers(Modifier.PUBLIC)
                            .returns(TypeName.VOID)
                            .addParameter(TypeUtil.ANDROID_VIEW, "view")
                            .addStatement("host.$N()", method.getMethodName())
                            .build())
                    .build();
            methodBuilder.addStatement("listener = $L ", listener);
            for (int id : method.ids) {
                methodBuilder.addStatement("finder.findView(source,$L).setOnClickListener(listener)", id);
            }
        }
        methodBuilder.addStatement("mapViewData.addOnMapChangedCallback(new androidx.databinding.ObservableMap.OnMapChangedCallback<androidx.databinding.ObservableMap<String, String>, String, String>() {\n" +
                "            @Override\n" +
                "            public void onMapChanged(ObservableMap<String, String> sender, String key) {\n" +
                "                if (mapFeildView.get(key) instanceof $T) {\n" +
                "                    if (!(((EditText) mapFeildView.get(key))).getText().toString().equals(sender.get(key))) {\n" +
                "                        (((EditText) mapFeildView.get(key))).setText(sender.get(key));\n" +
                "                        (((EditText) mapFeildView.get(key))).setSelection(sender.get(key).length());\n" +
                "                    }\n" +
                "                } else if (mapFeildView.get(key) instanceof $T) {\n" +
                "                     ((CheckBox) mapFeildView.get(key)).setChecked(sender.get(key).equals(\"true\"));" +
                "                } else if (mapFeildView.get(key) instanceof $T) {\n" +
                "                    if (!(((TextView) mapFeildView.get(key))).getText().toString().equals(sender.get(key))) {\n" +
                "                        (((TextView) mapFeildView.get(key))).setText(sender.get(key));\n" +
                "                    }\n" +
                "                } else if (mapFeildView.get(key) instanceof $T) {\n" +
                "                    RadioGroup group = (RadioGroup) mapFeildView.get(key);\n" +
                "                    for (int i = 0; i < group.getChildCount(); i++) {\n" +
                "                        if((($T)group.getChildAt(i)).getText().toString().equals(sender.get(key))){\n" +
                "                            if(group.getCheckedRadioButtonId()!=group.getChildAt(i).getId()){\n" +
                "                                group.check(group.getChildAt(i).getId());\n" +
                "                            }\n" +
                "                        }\n" +
                "                    }\n" +
                "                }else {\n" +
                "                    try {\n" +
                "                       getChildViewTag(mapFeildView.get(key));\n" +
                "                       if(null!=sonview){\n" +
                "int index=-1;\n"+
                "             for (int i = 0; i <sonview.size() ; i++) {\n" +
                "            String con =sonview.get(i).getText().toString();\n" +
                "            if(sonview.get(i) instanceof RadioButton){\n " +
                "                           notify = false;         ((RadioButton) sonview.get(i)).setChecked(false);\n" +
                "                                    if (null != con && con.equals(sender.get(key))) {\n" +
                "                                        index=i;\n" +
                "                                    }" +
                "          } else if(sonview.get(i) instanceof $T){\n" +
//                "       notify = false;          ((CheckBox) sonview.get(i)).setChecked(sender.get(key).equals(\"true\"));\n" +
                "            }else{\n" +
                "                           if (!(null != con && con.equals(sender.get(key)))) {\n" +
                "                               sonview.get(i).setText(sender.get(key));\n" +
                "                           }\n" +
                "            }\n" +
                "\n" +
                "        }" +
                "if(index!=-1){\n" +
                "                                    notify = false;\n" +
                "                                    ((RadioButton) sonview.get(index)).setChecked(true);\n notify = true;" +
                "                            }"+
                "                       }\n" +
                "                    } catch (Exception e) {\n" +
                "                        e.printStackTrace();\n" +
                "                    }\n" +
                "                }\n" +
                "            }\n" +
                "        })",ClassName.get("android.widget", "EditText"),ClassName.get("android.widget", "CheckBox"),ClassName.get("android.widget", "TextView"),ClassName.get("android.widget", "RadioGroup"),ClassName.get("android.widget", "RadioButton"),ClassName.get("android.widget", "CheckBox"));


        methodBuilder.addStatement("return this");

        // 定义包名
        String packageName = getPackageName(mClassElement);
        // 定义类名
        String className = getClassName(mClassElement, packageName);
        ClassName bindClassName = ClassName.get(packageName, className);

        MethodSpec.Builder methodBuildergetChildViewTag = MethodSpec.methodBuilder("getChildViewTag")
                .addModifiers(Modifier.PUBLIC)// 方法访问权限
                .addParameter(view, "view") // 定义方法的参数
                ;
methodBuildergetChildViewTag.addStatement("if (view instanceof $T) {\n" +
        "       sonview.clear();  \n     ViewGroup group = (ViewGroup) view;\n" +
        "            for (int i = 0, count = group.getChildCount(); i < count; i++) {\n" +
        "                 if (group.getChildAt(i) instanceof TextView ) {\n" +
        "                    if (null != group.getChildAt(i).getTag() && group.getChildAt(i).getTag().toString().startsWith(\"BTag:\")) {\n" +
        "                        sonview.add((TextView)group.getChildAt(i));\n" +
        "                  //      return;\n" +
        "                    }\n" +
        "                }else{\n" +
        "                    getChildViewTag(group.getChildAt(i));\n" +
        "                }\n" +
        "            }\n" +
        "        }",ViewGroup);
        MethodSpec.Builder methodBuilderSetData = MethodSpec.methodBuilder("setData")
                .addModifiers(Modifier.PUBLIC)// 方法访问权限
                .addParameter(string, "key") // 定义方法的参数
                .addParameter(string, "data");
        methodBuilderSetData.addStatement("mapViewData.put(key,data)");

        MethodSpec.Builder methodBuilderGetData = MethodSpec.methodBuilder("getData")
                .addModifiers(Modifier.PUBLIC)// 方法访问权限
                .addAnnotation(Override.class)
                .returns(string) // 定义方法的返回值
                .addParameter(string, "key");// 定义方法的参数
        methodBuilderGetData.addStatement(" return mapViewData.get(key)");

        MethodSpec.Builder methodBuilderGetDataAll = MethodSpec.methodBuilder("getData")
                .addModifiers(Modifier.PUBLIC)// 方法访问权限
                .addAnnotation(Override.class)
                .returns(ClassName.get("androidx.databinding", "ObservableArrayMap")); // 定义方法的返回值
        methodBuilderGetDataAll.addStatement(" return mapViewData");

        MethodSpec.Builder methodBuilderGetDelegate = MethodSpec.methodBuilder("init")
                .addModifiers(Modifier.PUBLIC)// 方法访问权限
                .addAnnotation(Override.class)
                .addParameter(ClassName.get("androidx.appcompat.app","AppCompatActivity"),"activity")
//                .returns(ClassName.get(packageName, className+ "$$Injector"))
                ;// 定义方法的返回值
        methodBuilderGetDelegate.addStatement("context=activity");
        methodBuilderGetDelegate.addStatement(
                "$T.setFactory2($T.from(activity),new LayoutInflater.Factory2(){\n" +
                        "            @Override\n" +
                        "            public View onCreateView(String name, Context context, $T attrs) {\n" +
                        "                return onCreateView(null,\"\",context,attrs);\n" +
                        "            }\n" +
                        "            @Override\n" +
                        "            public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {\n" +
                        "                switch(name){\n" +
                        "                    case \"TextView\":\n" +
                        "                        return  new com.ytg.myapi.view.SkinCompatTextView(context, attrs);\n" +
                        "                    case \"EditText\":\n" +
                        "                        return  new com.ytg.myapi.view.SkinCompatEditText(context, attrs);\n" +
                        "                    case \"CheckBox\":\n" +
                        "                        return  new com.ytg.myapi.view.SkinCompatCheckBox(context, attrs);\n" +
                        "                    case \"RadioGroup\":\n" +
                        "                        return  new com.ytg.myapi.view.SkinCompatRadioGroup(context, attrs);"+
                        "                }\n" +
                        "                return activity.getDelegate().createView(parent,name,context,attrs);\n" +
                        "            }\n" +
                        "        });"
        ,ClassName.get("androidx.core.view", "LayoutInflaterCompat"),ClassName.get("android.view", "LayoutInflater"),ClassName.get("android.util", "AttributeSet"));
        methodBuilderGetDelegate.addStatement("$T.getInstance().setTextBack(new $T() {\n" +
                "            @Override\n" +
                "            public void back(int id, String tag, String text) {\n" +
                "                if (null != tag && tag.startsWith(\"BTag:\")){\n" +
                "                    tag = tag.replace(\"BTag:\", \"\");\n" +
                "                    if (null!=getData(tag)&& !getData(tag).equals(text)) {\n" +
                "                        setData(tag, text);\n" +
                "                    }\n" +
                "                }\n" +
                "            }\n" +
                "        });\n" +
                "        ",ClassName.get("com.ytg.myapi", "BindWay"),ClassName.get("com.ytg.myapi.utils", "SetTextBack"));

        methodBuilderGetDelegate.addStatement("BindWay.getInstance().setCheckedBack(new $T() {\n" +
                "            @Override\n" +
                "            public void onCheckedChanged(RadioGroup group, int checkedId) {\n" +
                "if(!notify){notify = true;return ;} \n if(null==group.getTag()){return;}\n"+
                "                setData(group.getTag().toString().replace(\"BTag:\", \"\"),((RadioButton)group.findViewById(checkedId)).getText().toString());\n" +
                "            }\n" +
                "@Override\n" +
                "        public void onCheckedChanged($T buttonView, boolean isChecked) {\n" +
                "if(!notify){notify = true;return ;} \n "+
                "if(null==buttonView.getTag()){return;}"+
                "             setData(buttonView.getTag().toString().replace(\"BTag:\", \"\"), isChecked+\"\");\n \n" +
                "        }\n"+
                "        });",ClassName.get("com.ytg.myapi.utils", "SetCheckedBack"),ClassName.get("android.widget", "CompoundButton"));

        /**
         * 构建类
         */
        TypeSpec finderClass = TypeSpec.classBuilder(bindClassName.simpleName() + "$$Injector")
                .addModifiers(Modifier.PUBLIC)
                // 为当前类添加父类或者父接口
                .addSuperinterface(ParameterizedTypeName.get(TypeUtil.INJECTOR, TypeName.get(mClassElement.asType())))
                .addMethod(methodBuilder.build())// 将methodBuilder添加到类中
                .addMethod(methodBuildergetChildViewTag.build())
                .addMethod(methodBuilderSetData.build())
                .addMethod(methodBuilderGetData.build())
                .addMethod(methodBuilderGetDelegate.build())
                .addMethod(methodBuilderGetDataAll.build())
                .addField(fieldSpec17).addField(fieldSpec5)
                .addField(fieldSpec2).addField(fieldSpec10)
                .addField(fieldSpec3).addField(fieldSpec4).addField(fieldSpec9)
                .build();
        // 构建对应的java文件, 但是此时还没有生成对应的java文件
        return JavaFile.builder(packageName, finderClass).build();
    }

    public String getPackageName(TypeElement type) {
        return mElementUtils.getPackageOf(type).getQualifiedName().toString();
    }

    private static String getClassName(TypeElement type, String packageName) {
        int packageLen = packageName.length() + 1;
        return type.getQualifiedName().toString().substring(packageLen).replace('.', '$');
    }
}
